package com.sunda.spmsoversea.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmsoversea.dto.OverseaDeliveryNoteItemDTO;
import com.sunda.spmsoversea.dto.OverseaWhsInDTO;
import com.sunda.spmsoversea.dto.OverseaWhsInQueryDTO;
import com.sunda.spmsoversea.dto.OverseaWhsInUpdateDTO;
import com.sunda.spmsoversea.entity.*;
import com.sunda.spmsoversea.mapper.OverseaWhsInMapper;
import com.sunda.spmsoversea.service.*;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;

import static com.sunda.spmscommon.constant.OperationTypeConstant.OVERSEA_GET_BOX_NOTE;
import static com.sunda.spmsoversea.constant.CommonConstant.*;
import static com.sunda.spmsoversea.constant.MovementTypeConstant.*;
import static com.sunda.spmsoversea.constant.OverseaWhsInConstant.GET_BOX_NOTE;
import static com.sunda.spmsoversea.constant.SapConstant.DATA_STATUS_1;
import static com.sunda.spmsoversea.constant.SapConstant.SAP_SUCCESS;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.*;
import static com.sunda.spmsoversea.enums.OverseaDeliveryNoteEnum.*;
import static com.sunda.spmsoversea.enums.OverseaWhsInEnum.*;


/**
 * <p>
 * 海外仓入库任务表头 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-08-26
 */
@Service
@Slf4j
public class OverseaWhsInServiceImpl extends ServiceImpl<OverseaWhsInMapper, OverseaWhsIn> implements IOverseaWhsInService {

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;

    @Autowired
    IOverseaPackageListBoxService iOverseaPackageListBoxService;

    @Autowired
    IOverseaPackageListService iOverseaPackageListService;

    @Autowired
    IOverseaPackageListDtlService iOverseaPackageListDtlService;

    @Autowired
    IOverseaDeliveryNoteService iOverseaDeliveryNoteService;

    @Autowired
    IOverseaDeliveryNoteDtlService iOverseaDeliveryNoteDtlService;

    @Autowired
    IOverseaWhsInDtlService iOverseaWhsInDtlService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    /**
     {
     "createDate": "2021-10-27",
     "werks": "GF02",
     "whsLocationCode": "2006",
     "sapDeliveryNote": "0700442654",
     "overseaDeliveryNoteItem": [{
     "sapDeliveryNote": "0700442654",
     "sapDeliveryNoteItem": "10",
     "boxNote": "A",
     "boxNoteItem": "1"
     }, {
     "sapDeliveryNote": "0700442654",
     "sapDeliveryNoteItem": "30",
     "boxNote": "B",
     "boxNoteItem": "1"
     }]
     }
     * @param overseaWhsInDTO
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult createOverseaWhsIn(OverseaWhsInDTO overseaWhsInDTO, String userId) {
        /** 校验交货单数据是否为脏数据，是脏数据则返回错误信息 */
        ResponseResult checkDnValidate = iOverseaDeliveryNoteService.checkOverseaDeliveryNote(overseaWhsInDTO.getSapDeliveryNote());
        if (checkDnValidate.getCode() != SUCCESS){
            return checkDnValidate;
        }
        ResponseResult result = checkDataValidate(overseaWhsInDTO, userId);
        if (result.getCode() != SUCCESS){
            return result;
        }
        String uuidWhsIn = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
        String sapDeliveryNote = overseaWhsInDTO.getSapDeliveryNote();
        OverseaDeliveryNote overseaDeliveryNote = iOverseaDeliveryNoteService.getOverseaDn(sapDeliveryNote);

        try {
            if (OVERSEA_DN_WAITING.getCode().equals(overseaDeliveryNote.getSpmsStatus())){
                /** 交货单第一次拆分入库任务时，给海外仓收货交货单表，按 交货单号 更新状态为收货中，记录到货日期、收货工厂、仓库等信息 */
                updateOverseaDeliveryNote(overseaDeliveryNote, overseaWhsInDTO, OVERSEA_DN_RECEIVING.getCode());

                /** 交货单第一次生成入库任务，更新交货单关联的 交货单明细、装箱单、装箱单明细、装箱单箱码关系 数据锁定不再被SAP更新 */
                lockDataWithoutUpdateBySap(overseaDeliveryNote);

                iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, OVERSEA_DN_RECEIVING.getDescZh(), OVERSEA_DN_RECEIVING.getDescEn(), "");
            }

            /** 海运入库类型的任务即 装箱单号 字段值不为空，更新对应箱码状态为已到货，记录到货日期 */
            if (StringUtils.isNotEmpty(overseaDeliveryNote.getSapPackageList())){
                updateOverseaPackageListBoxNote(overseaWhsInDTO, userId);
            }

            /** 创建入库任务表头 */
            int createOverseaWhsInHeadResult = createOverseaWhsInHead(uuidWhsIn, overseaWhsInDTO, userId, overseaDeliveryNote);
            if (createOverseaWhsInHeadResult < 1){
                log.info("=======RuntimeException=========\n");
                throw new RuntimeException("创建入库任务表头错误");
            }

            /** 创建入库任务行项目 */
            int createOverseaWhsInItemResult = createOverseaWhsInItem(uuidWhsIn, overseaWhsInDTO, userId);
            if (createOverseaWhsInItemResult < 1){
                log.info("=======RuntimeException=========\n");
                throw new RuntimeException("创建入库任务行项目错误");
            }

            /** 记录入库任务创建日志 */
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_INIT.getDescZh(), OVERSEA_WHS_IN_INIT.getDescEn(), "");
            /** 交货单上记录入库任务创建日志 */
            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, OVERSEA_DN_CREATE_WHS_IN.getDescZh(), OVERSEA_DN_CREATE_WHS_IN.getDescEn(), "");
            /** 记录箱码海外到货日志，一个箱码多个明细，只记录一次到货 */
            addWhsOperateLog(overseaWhsInDTO, uuidWhsIn, userId);

            return ResponseResult.success()
                    .add("overseaWhsIn", this.baseMapper.selectOne(new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn)))
                    .add("overseaWhsInDtl", iOverseaWhsInDtlService.getOverseaWhsInDtlList(uuidWhsIn));
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("请求执行过程出错请重试").add("error", e.getMessage());
        }
    }

    void updateOverseaDeliveryNote(OverseaDeliveryNote overseaDeliveryNote, OverseaWhsInDTO overseaWhsInDTO, String targetStatus){
        overseaDeliveryNote.setSpmsStatus(targetStatus);
        overseaDeliveryNote.setDataStatus(DATA_STATUS_1);
        overseaDeliveryNote.setArrivalDate(overseaWhsInDTO.getCreateDate());
        overseaDeliveryNote.setActualWerksReceive(overseaWhsInDTO.getWerks());
        overseaDeliveryNote.setActualWhsLocationCodeReceive(overseaWhsInDTO.getWhsLocationCode());
        QueryWrapper<OverseaDeliveryNote> queryWrapper = new QueryWrapper<OverseaDeliveryNote>()
                .eq("SAP_DELIVERY_NOTE", overseaDeliveryNote.getSapDeliveryNote());
        iOverseaDeliveryNoteService.update(overseaDeliveryNote, queryWrapper);
    }

    void updateOverseaPackageListBoxNote(OverseaWhsInDTO overseaWhsInDTO, String userId){
        String arrivalDate = overseaWhsInDTO.getCreateDate();
        String werksReceive = overseaWhsInDTO.getWerks();
        String whsLocationCodeReceive = overseaWhsInDTO.getWhsLocationCode();
        List<OverseaDeliveryNoteItemDTO> itemDTOList = overseaWhsInDTO.getOverseaDeliveryNoteItem();
        for (int i = 0, len = itemDTOList.size(); i < len; i++){
            OverseaDeliveryNoteItemDTO itemDTO = itemDTOList.get(i);
            String boxNote = itemDTO.getBoxNote();
            if (StringUtils.isNotEmpty(boxNote)){
                iOverseaPackageListBoxService.updateOverseaPackageListBox(
                        boxNote, arrivalDate, userId, werksReceive, whsLocationCodeReceive);
            }
        }
    }

    int createOverseaWhsInHead (String uuidWhsIn, OverseaWhsInDTO overseaWhsInDTO, String userId, OverseaDeliveryNote overseaDeliveryNote){
        try {
            String werks = overseaWhsInDTO.getWerks();
            String whsLocationCode = overseaWhsInDTO.getWhsLocationCode();
            String createDate = overseaWhsInDTO.getCreateDate();
            OverseaWhsIn overseaWhsIn = new OverseaWhsIn();
            overseaWhsIn.setUuidWhsIn(uuidWhsIn);
            overseaWhsIn.setSapPackageList(overseaDeliveryNote.getSapPackageList());
            overseaWhsIn.setSapDeliveryNote(overseaDeliveryNote.getSapDeliveryNote());
            overseaWhsIn.setWerks(werks);
            overseaWhsIn.setWhsLocationCode(whsLocationCode);
            overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_RECEIVING.getCode());
            overseaWhsIn.setCreateDate(createDate);
            overseaWhsIn.setCreateUserid(userId);
            overseaWhsIn.setCabinetNumber(overseaDeliveryNote.getCabinetNumber());
            return this.baseMapper.insert(overseaWhsIn);
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    /** 记录箱码海外到货日志，一个箱码多个明细，只记录一次到货 */
    void addWhsOperateLog(OverseaWhsInDTO overseaWhsInDTO, String uuidWhsIn, String userId){
        List<OverseaDeliveryNoteItemDTO>  deliveryNoteItemDTOList = overseaWhsInDTO.getOverseaDeliveryNoteItem();
        Set set = new HashSet();
        for (OverseaDeliveryNoteItemDTO dto : deliveryNoteItemDTOList){
            String boxNote = dto.getBoxNote();
            if (!set.contains(boxNote)){
                String sapDeliveryNote = dto.getSapDeliveryNote();
                String werks = overseaWhsInDTO.getWerks();
                String whsLocationCode = overseaWhsInDTO.getWhsLocationCode();
                iWhsOperateLogService.recordGetBoxNote(boxNote, OVERSEA_GET_BOX_NOTE, sapDeliveryNote, uuidWhsIn, GET_BOX_NOTE,
                        userId, "", werks, whsLocationCode, "");
                set.add(boxNote);
            }
        }
    }

    int createOverseaWhsInItem (String uuidWhsIn, OverseaWhsInDTO overseaWhsInDTO, String userId){
        int addResult = 0;
        List<OverseaDeliveryNoteItemDTO> itemDTOList = overseaWhsInDTO.getOverseaDeliveryNoteItem();
        try {
            for (int i = 0, len = itemDTOList.size(); i < len; i++){
                OverseaDeliveryNoteItemDTO itemDTO = itemDTOList.get(i);
                String sapDeliveryNote = itemDTO.getSapDeliveryNote();
                String sapDeliveryNoteItem = itemDTO.getSapDeliveryNoteItem();
                String boxNote = itemDTO.getBoxNote();
                String boxNoteItem = itemDTO.getBoxNoteItem();
                //从装箱单明细箱码明细关系表信息创建入库任务明细
                OverseaDeliveryNoteDtl deliveryNoteDtl = iOverseaDeliveryNoteService.getDnDtl(sapDeliveryNote, sapDeliveryNoteItem);
                OverseaPackageListBox overseaPackageListBox = iOverseaPackageListBoxService.getOverseaPackageListBox(boxNote, boxNoteItem);
                if (overseaPackageListBox != null){
                    OverseaWhsInDtl overseaWhsInDtl = new OverseaWhsInDtl();
                    overseaWhsInDtl.setUuidWhsIn(uuidWhsIn);
                    overseaWhsInDtl.setItem(String.valueOf((i + 1) * 10));
                    overseaWhsInDtl.setMaterialNo(overseaPackageListBox.getMaterialNo());
                    overseaWhsInDtl.setBasicUnit(overseaPackageListBox.getBasicUnit());
                    overseaWhsInDtl.setUnitSales(deliveryNoteDtl.getUnitSales());
                    overseaWhsInDtl.setReceivableQtyBasicUnit(overseaPackageListBox.getReceivableQtyBasicUnit());
                    overseaWhsInDtl.setReceivableQtyUnitSales(0.0);
                    overseaWhsInDtl.setActualQtyBasicUnit(0.0);
                    overseaWhsInDtl.setActualQtyUnitSales(0.0);
                    overseaWhsInDtl.setStorageInfo("[]");
                    overseaWhsInDtl.setBoxNote(boxNote);
                    overseaWhsInDtl.setBoxNoteItem(boxNoteItem);
                    overseaWhsInDtl.setSapDeliveryNote(sapDeliveryNote);
                    overseaWhsInDtl.setSapDeliveryNoteItem(sapDeliveryNoteItem);
                    overseaWhsInDtl.setReceivableWerks(deliveryNoteDtl.getWerksReceive());
                    overseaWhsInDtl.setReceivableWhsLocationCode(deliveryNoteDtl.getWhsLocationCodeReceive());
                    overseaWhsInDtl.setActualWerks(overseaWhsInDTO.getWerks());
                    overseaWhsInDtl.setActualWhsLocationCode(overseaWhsInDTO.getWhsLocationCode());
                    addResult += iOverseaWhsInDtlService.addOverseaWhsInDtl(overseaWhsInDtl);
                }
                /***
                //从交货单明细表获取信息创建入库任务明细，修改为从箱码明细获取入库任务明细 ————2021-11-08
                OverseaDeliveryNoteDtl deliveryNoteDtl = iOverseaDeliveryNoteService.getDnDtl(sapDeliveryNote, sapDeliveryNoteItem);
                if (deliveryNoteDtl != null){
                    OverseaWhsInDtl overseaWhsInDtl = new OverseaWhsInDtl();
                    overseaWhsInDtl.setUuidWhsIn(uuidWhsIn);
                    overseaWhsInDtl.setItem(String.valueOf((i + 1) * 10));
                    overseaWhsInDtl.setMaterialNo(deliveryNoteDtl.getMaterialNo());
                    overseaWhsInDtl.setBasicUnit(deliveryNoteDtl.getBasicUnit());
                    overseaWhsInDtl.setUnitSales(deliveryNoteDtl.getUnitSales());
                    if (deliveryNoteDtl.getReceivableQtyBasicUnit() != null &&
                            StringUtils.isNotEmpty(deliveryNoteDtl.getReceivableQtyBasicUnit().toString())){
                        overseaWhsInDtl.setReceivableQtyBasicUnit(deliveryNoteDtl.getReceivableQtyBasicUnit());
                    } else {
                        overseaWhsInDtl.setReceivableQtyBasicUnit(0.0);
                    }
                    if (deliveryNoteDtl.getReceivableQtyUnitSales() != null &&
                            StringUtils.isNotEmpty(deliveryNoteDtl.getReceivableQtyUnitSales().toString())){
                        overseaWhsInDtl.setReceivableQtyUnitSales(deliveryNoteDtl.getReceivableQtyUnitSales());
                    } else {
                        overseaWhsInDtl.setReceivableQtyUnitSales(0.0);
                    }
                    overseaWhsInDtl.setActualQtyBasicUnit(0.0);
                    overseaWhsInDtl.setActualQtyUnitSales(0.0);
                    overseaWhsInDtl.setStorageInfo("[]");
                    overseaWhsInDtl.setBoxNote(boxNote);
                    overseaWhsInDtl.setSapDeliveryNote(sapDeliveryNote);
                    overseaWhsInDtl.setSapDeliveryNoteItem(sapDeliveryNoteItem);
                    overseaWhsInDtl.setReceivableWerks(deliveryNoteDtl.getWerksReceive());
                    overseaWhsInDtl.setReceivableWhsLocationCode(deliveryNoteDtl.getWhsLocationCodeReceive());
                    overseaWhsInDtl.setActualWerks(overseaWhsInDTO.getWerks());
                    overseaWhsInDtl.setActualWhsLocationCode(overseaWhsInDTO.getWhsLocationCode());
                    addResult += iOverseaWhsInDtlService.addOverseaWhsInDtl(overseaWhsInDtl);
                }
                 ***/
            }
            return addResult;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    ResponseResult checkDataValidate(OverseaWhsInDTO overseaWhsInDTO, String userId){
        if (StringUtils.isEmpty(userId) || overseaWhsInDTO == null){
            return ResponseResult.error("请求参数错误");
        }
        String sapDeliveryNote = overseaWhsInDTO.getSapDeliveryNote();
        if (StringUtils.isEmpty(overseaWhsInDTO.getCreateDate())
                || StringUtils.isEmpty(overseaWhsInDTO.getWerks())
                || StringUtils.isEmpty(overseaWhsInDTO.getWhsLocationCode())
                || StringUtils.isEmpty(sapDeliveryNote)){
            return ResponseResult.error("请求参数错误");
        }
        List<OverseaDeliveryNoteItemDTO> itemDTOList = overseaWhsInDTO.getOverseaDeliveryNoteItem();
        if (itemDTOList == null || itemDTOList.size() == 0){
            return ResponseResult.error("入库任务明细行数据不能为空");
        }
        for (int i = 0, len = itemDTOList.size(); i < len; i ++){
            OverseaDeliveryNoteItemDTO itemDTO = itemDTOList.get(i);
            if (StringUtils.isEmpty(itemDTO.getSapDeliveryNote())){
                return ResponseResult.error("交货单号不能为空");
            }
            if (StringUtils.isEmpty(itemDTO.getSapDeliveryNoteItem())){
                return ResponseResult.error("交货单行号不能为空");
            }
            if (StringUtils.isEmpty(itemDTO.getBoxNote()) || StringUtils.isEmpty(itemDTO.getBoxNoteItem())){
                return ResponseResult.error("箱码或箱码明细行号信息错误");
            }
        }
        OverseaDeliveryNote overseaDeliveryNote = iOverseaDeliveryNoteService.getOverseaDn(sapDeliveryNote);
        if (overseaDeliveryNote == null){
            return ResponseResult.error("交货单查询不存在");
        }
        String spmsStatus = overseaDeliveryNote.getSpmsStatus();
        if (!OVERSEA_DN_WAITING.getCode().equals(spmsStatus)
                && !OVERSEA_DN_RECEIVING.getCode().equals(spmsStatus)
                && !OVERSEA_DN_SUBMIT_OA_ERROR.getCode().equals(spmsStatus)){
            return ResponseResult.error("当前状态禁止此操作");
        }
        return ResponseResult.success();
    }

    /** 交货单第一次生成入库任务，更新交货单关联的 交货单明细、装箱单、装箱单明细、装箱单箱码关系 数据锁定不再被SAP更新 */
    void lockDataWithoutUpdateBySap(OverseaDeliveryNote overseaDeliveryNote){
        String sapDeliveryNote = overseaDeliveryNote.getSapDeliveryNote();
        String sapPackageList = overseaDeliveryNote.getSapPackageList();

        QueryWrapper<OverseaDeliveryNoteDtl> deliveryNoteDtlQueryWrapper = new QueryWrapper<OverseaDeliveryNoteDtl>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
        QueryWrapper<OverseaPackageList> packageListQueryWrapper = new QueryWrapper<OverseaPackageList>().eq("SAP_PACKAGE_LIST", sapPackageList);
        QueryWrapper<OverseaPackageListDtl> packageListDtlQueryWrapper = new QueryWrapper<OverseaPackageListDtl>().eq("SAP_PACKAGE_LIST", sapPackageList);
        QueryWrapper<OverseaPackageListBox> packageListBoxQueryWrapper = new QueryWrapper<OverseaPackageListBox>().eq("SAP_PACKAGE_LIST", sapPackageList);

        OverseaDeliveryNoteDtl overseaDeliveryNoteDtl = new OverseaDeliveryNoteDtl();
        overseaDeliveryNoteDtl.setDataStatus(DATA_STATUS_1);
        iOverseaDeliveryNoteDtlService.update(overseaDeliveryNoteDtl, deliveryNoteDtlQueryWrapper);

        OverseaPackageList overseaPackageList = new OverseaPackageList();
        overseaPackageList.setDataStatus(DATA_STATUS_1);
        iOverseaPackageListService.update(overseaPackageList, packageListQueryWrapper);

        OverseaPackageListDtl overseaPackageListDtl = new OverseaPackageListDtl();
        overseaPackageListDtl.setDataStatus(DATA_STATUS_1);
        iOverseaPackageListDtlService.update(overseaPackageListDtl, packageListDtlQueryWrapper);

        OverseaPackageListBox overseaPackageListBox = new OverseaPackageListBox();
        overseaPackageListBox.setDataStatus(DATA_STATUS_1);
        iOverseaPackageListBoxService.update(overseaPackageListBox, packageListBoxQueryWrapper);
    }

    @Override
    public IPage getOverseaWhsInPage(OverseaWhsInQueryDTO overseaWhsInQueryDTO) {
        IPage iPage = overseaWhsInQueryDTO.getPage();
        List<Map<String, Object>> mapList = this.baseMapper.getOverseaWhsInPage(iPage, overseaWhsInQueryDTO);
        iPage.setRecords(mapList);
        return iPage;
    }

    /**
     * SPMS_STATUS: 入库任务状态(默认0待入库;1入库中;2入库完成;3审批通过;4提交SAP成功;5提交SAP失败;6已撤销;7关闭;)
     "更新入库任务及明细" +
     "SPMS_STATUS: 入库任务状态(默认0待入库;1入库中;2入库完成;3审批通过;4提交SAP成功;5提交SAP失败;6已撤销;7关闭;)" +
     "待入库0          保存到 1，提交到 2，关闭到 7；    0-1，0-2，0-7；" +
     "入库中1          保存到 1，提交到 2，关闭到 7；    1-1，1-2，1-7；" +
     "入库完成2        审批不通过到 1，审批通过到 3；     2-1，2-3；     （2-3成功则增加库存）" +
     "审批通过3        撤销到 2，提交SAP；              3-2，3-4，3-5；（3-2成功则需扣减库存）" +
     "提交SAP成功4     撤销到 6；                      4-6；          （4-6撤销成功则扣减库存，单据状态更为6或7或1待定）" +
     "提交SAP失败5     撤销到 2，提交SAP；              5-2，5-4，5-5；（5-2成功则需扣减库存）" +
     "已撤销6          无操作" +
     "关闭7            无操作" +
     * @param overseaWhsInUpdateDTO
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult updateOverseaWhsIn(OverseaWhsInUpdateDTO overseaWhsInUpdateDTO, String userId) {
        try {
            ResponseResult result = checkUpdateOverseaWhsIn(overseaWhsInUpdateDTO);
            if (result.getCode() != SUCCESS){
                return result;
            }
            String uuidWhsIn = overseaWhsInUpdateDTO.getUuidWhsIn();
            String targetStatus = overseaWhsInUpdateDTO.getSpmsStatus();
            QueryWrapper<OverseaWhsIn> overseaWhsInQueryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
            OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(overseaWhsInQueryWrapper);

            /** 0-1，0-2，1-1，1-2，2-3 保存、提交、入库完成、审批通过都要更新入库任务表头 */
            ResponseResult updateOverseaWhsInHeadResult = updateOverseaWhsInHead(overseaWhsInUpdateDTO, overseaWhsIn);
            if (updateOverseaWhsInHeadResult.getCode() != SUCCESS){
                log.info("=======RuntimeException=========\n" + updateOverseaWhsInHeadResult.getMsg());
                throw new RuntimeException(updateOverseaWhsInHeadResult.getMsg());
            }

            /** 0-1，0-2，1-1，1-2，2-3 保存、提交、入库完成、审批通过都要更新入库任务明细行数据 */
            ResponseResult updateOverseaWhsInDtlResult = updateOverseaWhsInDtl(overseaWhsInUpdateDTO);
            if (updateOverseaWhsInDtlResult.getCode() != SUCCESS){
                log.info("=======RuntimeException=========\n" + updateOverseaWhsInDtlResult.getMsg());
                throw new RuntimeException(updateOverseaWhsInDtlResult.getMsg());
            }

            /** 0-1，0-2，1-1，1-2，2-3 保存、提交、入库完成、审批通过都要增加单据操作日志信息 */
            addOperateLog(uuidWhsIn, targetStatus, userId);

            /** 2-3 审批通过状态需要更新库存，同时按 箱码 + 箱码行号，将实际收货数量等信息回写进 装箱单明细箱码明细表中 */
            if (targetStatus.equals(OVERSEA_WHS_IN_APPROVE.getCode())){

                updateOverseaPackageListBox(overseaWhsIn, overseaWhsInUpdateDTO);

                ResponseResult updateStorageInventory = updateWhsStorageInventory(uuidWhsIn, ADD, userId, OPERATION_TYPE2,
                        overseaWhsIn.getWerks(), overseaWhsIn.getWhsLocationCode(), M101, "海运收货入库");
                if (updateStorageInventory.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateStorageInventory.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateStorageInventory.getMsg());
                }
            }
            return ResponseResult.success()
                    .add("overseaWhsIn", this.baseMapper.selectOne(overseaWhsInQueryWrapper))
                    .add("getOverseaWhsInDtlList", iOverseaWhsInDtlService.getOverseaWhsInDtlList(uuidWhsIn));
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    ResponseResult updateOverseaWhsInHead(OverseaWhsInUpdateDTO overseaWhsInUpdateDTO, OverseaWhsIn overseaWhsIn){
        String uuidWhsIn = overseaWhsInUpdateDTO.getUuidWhsIn();
        QueryWrapper<OverseaWhsIn> overseaWhsInQueryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
        overseaWhsIn.setSpmsStatus(overseaWhsInUpdateDTO.getSpmsStatus());
        overseaWhsIn.setRemarks(overseaWhsInUpdateDTO.getRemarks() == null ? "" : overseaWhsInUpdateDTO.getRemarks());
        overseaWhsIn.setComments(overseaWhsInUpdateDTO.getComments() == null ? "" : overseaWhsInUpdateDTO.getComments());
        this.baseMapper.update(overseaWhsIn, overseaWhsInQueryWrapper);
        return ResponseResult.success();
    }

    ResponseResult updateOverseaWhsInDtl(OverseaWhsInUpdateDTO overseaWhsInUpdateDTO){
        List<OverseaWhsInDtl> overseaWhsInDtlList = overseaWhsInUpdateDTO.getOverseaWhsInDtlList();
        for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
            iOverseaWhsInDtlService.updateOverseaWhsInDtl(overseaWhsInDtl);
        }
        return ResponseResult.success();
    }

    /** 按 箱码 + 箱码行号，将实际收货数量等信息回写进 装箱单明细箱码明细表中 */
    void updateOverseaPackageListBox(OverseaWhsIn overseaWhsIn, OverseaWhsInUpdateDTO overseaWhsInUpdateDTO){
        String werks = overseaWhsIn.getWerks();
        String whsLocationCode = overseaWhsIn.getWhsLocationCode();
        List<OverseaWhsInDtl> overseaWhsInDtlList = overseaWhsInUpdateDTO.getOverseaWhsInDtlList();
        for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
            String boxNote = overseaWhsInDtl.getBoxNote();
            String boxNoteItem = overseaWhsInDtl.getBoxNoteItem();
            double operateQty = overseaWhsInDtl.getActualQtyBasicUnit();
            if (operateQty > 0){
                QueryWrapper<OverseaPackageListBox> queryWrapperPLB = new QueryWrapper<OverseaPackageListBox>()
                        .eq("BOX_NOTE", boxNote).eq("BOX_NOTE_ITEM", boxNoteItem);
                OverseaPackageListBox overseaPackageListBox = iOverseaPackageListBoxService.getOne(queryWrapperPLB);
                overseaPackageListBox.setWerksReceive(werks);
                overseaPackageListBox.setWhsLocationCodeReceive(whsLocationCode);
                overseaPackageListBox.setActualQtyBasicUnit(overseaPackageListBox.getActualQtyBasicUnit() + operateQty);
                iOverseaPackageListBoxService.update(overseaPackageListBox, queryWrapperPLB);
            }
        }
    }

    /**
     * @param uuidWhsIn
     * @param operateType  库存操作类型，加库存还是减库存；
     * @param userId
     * @param logType  记录库存操作日志类型，2上架(加储位库存);3下架(减储位库存)...
     * @param werks
     * @param whsLocationCode
     * @return
     */
    synchronized ResponseResult updateWhsStorageInventory(String uuidWhsIn, String operateType, String userId, String logType, String werks, String whsLocationCode, String movementType, String remark){
        List<OverseaWhsInDtl> overseaWhsInDtlList = iOverseaWhsInDtlService.getOverseaWhsInDtls(uuidWhsIn);
        if (overseaWhsInDtlList == null || overseaWhsInDtlList.size() == 0){
            return ResponseResult.error("入库任务明细数据查询不存在");
        }
        for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
            String materialNo = overseaWhsInDtl.getMaterialNo();
            double actualQtyBasicUnit = overseaWhsInDtl.getActualQtyBasicUnit() == null ? 0 : overseaWhsInDtl.getActualQtyBasicUnit();
            if (actualQtyBasicUnit > 0){
                //storageInfoArray 结构参考：[{"storageUuid":"f17e13b4d9ad4d39ba55548eff544391","qty":100,"storageNo":"C010101"}]
                JSONArray storageInfoArray = JSONArray.parseArray(overseaWhsInDtl.getStorageInfo());
                for (int i = 0; i < storageInfoArray.size(); i ++){
                    JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                    String storageUuid = storageInfoObj.getString("storageUuid");
                    double qty = storageInfoObj.getDoubleValue("qty");
                    if (qty > 0){
                        ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, operateType);
                        if (updateInventory.getCode() != SUCCESS){
                            return updateInventory;
                        }
                        String comments = operateType.equals(ADD) ? WHS_OPERATE_LOG_ADD : WHS_OPERATE_LOG_SUB;
                        iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, logType, uuidWhsIn, comments, userId, remark, werks, whsLocationCode, movementType);
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    void addOperateLog(String uuidWhsIn, String targetStatus, String userId){
        if (targetStatus.equals(OVERSEA_WHS_IN_RECEIVING.getCode())){
            //入库中 1
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_RECEIVING.getDescZh(), OVERSEA_WHS_IN_RECEIVING.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_COMPLETE.getCode())){
            //入库完成 2
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_COMPLETE.getDescZh(), OVERSEA_WHS_IN_COMPLETE.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_APPROVE.getCode())){
            //审批通过 3
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_APPROVE.getDescZh(), OVERSEA_WHS_IN_APPROVE.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP.getCode())){
            //提交SAP成功 4
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_SUBMIT_SAP.getDescZh(), OVERSEA_WHS_IN_SUBMIT_SAP.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getCode())){
            //提交SAP失败 5
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getDescZh(), OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_CANCEL.getCode())){
            //已撤销 6
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_CANCEL.getDescZh(), OVERSEA_WHS_IN_CANCEL.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_CLOSE.getCode())){
            //已关闭 7
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_CLOSE.getDescZh(), OVERSEA_WHS_IN_CLOSE.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_GO_BACK.getCode())){
            //退回单据 -1
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_GO_BACK.getDescZh(), OVERSEA_WHS_IN_GO_BACK.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_IN_REJECT.getCode())){
            //审批不通过 -2
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_REJECT.getDescZh(), OVERSEA_WHS_IN_REJECT.getDescEn(), "");
        }

    }

    ResponseResult checkUpdateOverseaWhsIn(OverseaWhsInUpdateDTO overseaWhsInUpdateDTO){
        String sapDeliveryNote = overseaWhsInUpdateDTO.getSapDeliveryNote();
        String uuidWhsIn = overseaWhsInUpdateDTO.getUuidWhsIn();
        String targetStatus = overseaWhsInUpdateDTO.getSpmsStatus();
        int dataVersion = overseaWhsInUpdateDTO.getDataVersion() == null ? -1 : overseaWhsInUpdateDTO.getDataVersion();
        if (StringUtils.isEmpty(uuidWhsIn) || StringUtils.isEmpty(targetStatus)){
            return ResponseResult.error("请求参数错误请重试");
        }
        if (!(targetStatus.equals(OVERSEA_WHS_IN_RECEIVING.getCode()) || targetStatus.equals(OVERSEA_WHS_IN_COMPLETE.getCode())
                || targetStatus.equals(OVERSEA_WHS_IN_APPROVE.getCode()))){
            return ResponseResult.error("请求参数目标状态错误");
        }
        OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn));
        if (overseaWhsIn == null){
            return ResponseResult.error("请求入库任务不存在");
        }
        if (overseaWhsIn.getDataVersion() == null || dataVersion != overseaWhsIn.getDataVersion()){
            return ResponseResult.error("请求数据已更新请刷新重试");
        }
        List<OverseaWhsInDtl> overseaWhsInDtlList = overseaWhsInUpdateDTO.getOverseaWhsInDtlList();
        if (overseaWhsInDtlList == null || overseaWhsInDtlList.size() == 0){
            return ResponseResult.error("请求参数入库任务明细不能为空");
        }

        /**
         * 交货单行不允许多收，此处获取交货单每一行数据  实收数量、剩余应收数量信息，
         * 如果 入库任务行实收数据 大于 交货单行剩余应收数量，则为错误不允许提交 */
        if (targetStatus.equals(OVERSEA_WHS_IN_COMPLETE.getCode())){
            List<Map<String, Object>> getOverchargedDnItem = this.baseMapper.getOverchargedDnItem(sapDeliveryNote);
            String errorMsg = "";
            for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
                String sapDeliveryNoteItem = overseaWhsInDtl.getSapDeliveryNoteItem();
                double actualQtyBasicUnit = overseaWhsInDtl.getActualQtyBasicUnit();
                for (Map<String, Object> map : getOverchargedDnItem){
                    if (sapDeliveryNoteItem.equals(map.get("sapDeliveryNoteItem").toString())){
                        double remainingReceivableQtyBasicUnit = Double.parseDouble(map.get("remainingReceivableQtyBasicUnit").toString());
                        if (actualQtyBasicUnit > remainingReceivableQtyBasicUnit){
                            log.info("入库任务" + overseaWhsIn.getWhsInNo() + "  入库任务行号" + overseaWhsInDtl.getItem()
                                    + "  物料编号" + map.get("materialNo") + "  收货数量" + actualQtyBasicUnit
                                    + "  大于交货单该行剩余应收数量" + remainingReceivableQtyBasicUnit);
                            errorMsg += "入库任务" + overseaWhsIn.getWhsInNo() + "  行号" + overseaWhsInDtl.getItem() + "  物料编号" + map.get("materialNo") +
                                    "  收货数量" + actualQtyBasicUnit + "  大于交货单该行剩余应收数量" + remainingReceivableQtyBasicUnit + "--";
                        }
                    }
                }
            }
            if (StringUtils.isNotEmpty(errorMsg)){
                return ResponseResult.error(errorMsg);
            }
        }

        /** 实收数量不为 0 的行数据，储位信息一定要有有效值； */
        for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
            if (overseaWhsInDtl.getAutoIdWhsInDtl() == null){
                return ResponseResult.error("请求参数入库任务明细参数错误");
            }
            String item = overseaWhsInDtl.getItem();
            String materialNo = overseaWhsInDtl.getMaterialNo();
            int autoIdWhsInDtl = overseaWhsInDtl.getAutoIdWhsInDtl();
            double actualQtyBasicUnit = overseaWhsInDtl.getActualQtyBasicUnit() == null ? 0 : StringUtils.isEmpty(overseaWhsInDtl.getActualQtyBasicUnit().toString()) ? 0 : overseaWhsInDtl.getActualQtyBasicUnit();
            double actualQtyUnitSales = overseaWhsInDtl.getActualQtyUnitSales() == null ? 0 : StringUtils.isEmpty(overseaWhsInDtl.getActualQtyUnitSales().toString()) ? 0 : overseaWhsInDtl.getActualQtyUnitSales();
            String storageInfo = overseaWhsInDtl.getStorageInfo();
            if (actualQtyUnitSales > 0 && actualQtyBasicUnit > 0){
                if ("[]".equals(storageInfo) || StringUtils.isEmpty(storageInfo)){
                    return ResponseResult.error("实收数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                }
            }
        }
        return ResponseResult.success();
    }

    @Override
    public synchronized ResponseResult closeOverseaWhsIn(String uuidWhsIn, int dataVersion, String userId) {
        if (StringUtils.isEmpty(uuidWhsIn)){
            return ResponseResult.error("请求参数错误");
        }
        QueryWrapper<OverseaWhsIn> queryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
        OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(queryWrapper);
        if (overseaWhsIn == null){
            return ResponseResult.error("请求入库任务不存在");
        }
        if (dataVersion != overseaWhsIn.getDataVersion()){
            return ResponseResult.error("请求数据已更新请刷新重试");
        }
        String spmsStatus = overseaWhsIn.getSpmsStatus();
        if (!OVERSEA_WHS_IN_WAITING.getCode().equals(spmsStatus) && !OVERSEA_WHS_IN_RECEIVING.getCode().equals(spmsStatus)){
            return ResponseResult.error("当前状态禁止此操作");
        }
        overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_CLOSE.getCode());
        int updateResult = this.baseMapper.update(overseaWhsIn, queryWrapper);
        if (updateResult == 1){
            addOperateLog(uuidWhsIn, OVERSEA_WHS_IN_CLOSE.getCode(), userId);
            return ResponseResult.success().add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper));
        }
        return ResponseResult.error("请求更新失败");
    }

    /**
     SPMS_STATUS: 入库任务状态(默认0待入库; 1入库中; 2入库完成; 3审批通过; 4提交SAP成功; 5提交SAP失败; 6已撤销; 7关闭;)
     撤销/退回单据，更新表头：2-1，3-1（减库存），4-1（减库存），5-1（减库存） */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult cancelOverseaWhsIn(String uuidWhsIn, String cancelPostingDate, int dataVersion, String userId) {
        ResponseResult checkResult = checkCancelOverseaWhsIn(uuidWhsIn, cancelPostingDate, dataVersion);
        if (checkResult.getCode() != SUCCESS){
            return checkResult;
        }
        QueryWrapper<OverseaWhsIn> queryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
        OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(queryWrapper);
        List<OverseaWhsInDtl> overseaWhsInDtlList = iOverseaWhsInDtlService.getOverseaWhsInDtls(uuidWhsIn);
        String spmsStatus = overseaWhsIn.getSpmsStatus();
        try{
            if (spmsStatus.equals(OVERSEA_WHS_IN_COMPLETE.getCode())){
                overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_RECEIVING.getCode());
                this.baseMapper.update(overseaWhsIn, queryWrapper);
                addOperateLog(uuidWhsIn, OVERSEA_WHS_IN_GO_BACK.getCode(), userId);
                return ResponseResult.success().add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper));
            }
            /** 审批通过撤回 和 提交SAP失败撤回操作过程一致：更新表头、记录日志、更新库存；OVERSEA_PACKAGE_LIST_BOX 记录实收信息也一并扣减； */
            if (spmsStatus.equals(OVERSEA_WHS_IN_APPROVE.getCode()) ||
                    spmsStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getCode())){
                overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_RECEIVING.getCode());
                this.baseMapper.update(overseaWhsIn, queryWrapper);
                addOperateLog(uuidWhsIn, OVERSEA_WHS_IN_REJECT.getCode(), userId);

                /** 将箱码每一行实收信息进行更新 */
                delOverseaPackageListBox(overseaWhsInDtlList);

                ResponseResult updateInventory = updateWhsStorageInventory(uuidWhsIn, SUB, userId, OPERATION_TYPE3, overseaWhsIn.getWerks(), overseaWhsIn.getWhsLocationCode(), M102, "海运入库撤销");
                if (updateInventory.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateInventory.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateInventory.getMsg());
                }
                return ResponseResult.success().add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper));
            }
            if (spmsStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP.getCode())){
                JSONObject dataToSap = cancelToSap(overseaWhsIn, cancelPostingDate);
                log.info("=======dataToSap=========\n" + dataToSap);
                JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                log.info("=======message=========\n" + message);
                JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                if (SAP_SUCCESS.equals(RETURN_DATA.getString("O_TYPE"))) {
                    String cancelVoucherNumber = RETURN_DATA.getString("0_MBLNR");
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_CANCEL.getDescZh() + ":" + cancelVoucherNumber,
                            OVERSEA_WHS_IN_CANCEL.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "入库任务撤销提交SAP");
                    overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_RECEIVING.getCode());
                    overseaWhsIn.setCancelPostingDate(cancelPostingDate);
                    overseaWhsIn.setCancelVoucherNumber(cancelVoucherNumber);
                    this.baseMapper.update(overseaWhsIn, queryWrapper);

                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_RECEIVING.getDescZh(),
                            OVERSEA_WHS_IN_RECEIVING.getDescEn(), "");

                    /** 将箱码每一行实收信息进行更新 */
                    delOverseaPackageListBox(overseaWhsInDtlList);

                    ResponseResult updateInventory = updateWhsStorageInventory(uuidWhsIn, SUB, userId, OPERATION_TYPE3, overseaWhsIn.getWerks(), overseaWhsIn.getWhsLocationCode(), M102, "海运入库撤销");
                    if (updateInventory.getCode() != SUCCESS){
                        log.info("=======RuntimeException=========\n" + updateInventory.getMsg());
                        throw new RuntimeException("储位库存更新错误\n" + updateInventory.getMsg());
                    }

                    return ResponseResult.success()
                            .add("sapReturnedMessage", message)
                            .add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper))
                            .add("overseaWhsInDtl", iOverseaWhsInDtlService.getOverseaWhsInDtlList(uuidWhsIn))
                            .add("dataToSap", dataToSap);

                }else {
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsIn, OVERSEA_WHS_IN_CANCEL_ERROR.getDescZh(),
                            OVERSEA_WHS_IN_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "入库任务撤销提交SAP");
                    return ResponseResult.error()
                            .add("sendSapReturnedMessage", message)
                            .add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper))
                            .add("dataToSap", dataToSap);

                }
            }
            return ResponseResult.error("请求入库任务状态禁止此操作");
        }catch (FeignException feignException) {
            feignException.printStackTrace();
            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
        } catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    /** 撤销/退回单据，更新表头：2-1，3-1（减库存），4-1（减库存），5-1（减库存）
     * 涉及库存扣减操作时，需要同时更新 OVERSEA_PACKAGE_LIST_BOX表，将箱码每一行实收信息进行更新 */
    void delOverseaPackageListBox(List<OverseaWhsInDtl> overseaWhsInDtlList){
        for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
            String boxNote = overseaWhsInDtl.getBoxNote();
            String boxNoteItem = overseaWhsInDtl.getBoxNoteItem();
            double operateQty = overseaWhsInDtl.getActualQtyBasicUnit();
            if (operateQty > 0){
                iOverseaPackageListBoxService.updateOverseaPackageListBoxQty(boxNote, boxNoteItem, operateQty, SUB);
            }
        }
    }

    JSONObject cancelToSap(OverseaWhsIn overseaWhsIn, String cancelPostingDate){
        JSONObject doc = new JSONObject();

        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject Head = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
        Head.put("iMblnr", overseaWhsIn.getSapVoucherNumber());
        Head.put("iMjahr", overseaWhsIn.getSapVoucherYear());
        Head.put("iBudat", cancelPostingDate.replaceAll("-", ""));
        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("Operation", "Z_SPMS_CANCEL");
        REQUEST_DATA.put("Type", "SPMS_CANCEL");
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        doc.put("REQUEST", REQUEST);
        return doc;
    }

    /**
     * 入库任务状态(默认0待入库;1入库中;2入库完成;3审批通过;4提交SAP成功;5提交SAP失败;6已撤销;7关闭;)
     * 撤销/退回单据，更新表头：2-1，3-1（减库存），4-1（减库存），5-1（减库存），只有2，3，4，5状态单据可撤销/退回 */
    ResponseResult checkCancelOverseaWhsIn(String uuidWhsIn, String cancelPostingDate, int dataVersion){
        if (StringUtils.isEmpty(uuidWhsIn)){
            return ResponseResult.error("请求参数错误");
        }
        QueryWrapper<OverseaWhsIn> queryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
        OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(queryWrapper);
        if (overseaWhsIn == null){
            return ResponseResult.error("请求入库任务不存在");
        }
        if (dataVersion != overseaWhsIn.getDataVersion()){
            return ResponseResult.error("请求数据已更新请刷新重试");
        }
        List<OverseaWhsInDtl> overseaWhsInDtlList = iOverseaWhsInDtlService.getOverseaWhsInDtls(uuidWhsIn);
        if (overseaWhsInDtlList == null || overseaWhsInDtlList.size() == 0){
            return ResponseResult.error("请求入库任务明细行不存在");
        }
        String spmsStatus = overseaWhsIn.getSpmsStatus();
        String sapDeliveryNote = overseaWhsIn.getSapDeliveryNote();
        /** 如果入库任务关联的交货单状态不为收货中，则禁止入库任务撤回操作 */
        OverseaDeliveryNote overseaDeliveryNote = iOverseaDeliveryNoteService.getOverseaDn(sapDeliveryNote);
        if (!OVERSEA_DN_RECEIVING.getCode().equals(overseaDeliveryNote.getSpmsStatus())){
            return ResponseResult.error("入库任务关联交货单状态为-已完成入库或收货完成，请先撤回交货单状态为-收货中");
        }
        if (spmsStatus.equals(OVERSEA_WHS_IN_COMPLETE.getCode())){
            /** 退回单据，入库完成——入库中，2-1，无校验；*/
        }else if (spmsStatus.equals(OVERSEA_WHS_IN_APPROVE.getCode())){
            /** 撤销单据，审批通过——入库完成，3-1（减库存），需判断入库任务明细行数据储位库存是否够扣减；*/
            ResponseResult checkInventory = checkMaterialInventory(overseaWhsIn, overseaWhsInDtlList);
            if (checkInventory.getCode() != SUCCESS){
                return checkInventory;
            }
        }else if (spmsStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP.getCode())) {
            /** 撤销单据，提交SAP成功——从SAP撤销，4-1（减库存），需判断入库任务明细行数据储位库存是否够扣减；cancelPostingDate 不为空；*/
            if (StringUtils.isEmpty(cancelPostingDate)){
                return ResponseResult.error("撤销SAP过账日期不能为空");
            }
            ResponseResult checkInventory = checkMaterialInventory(overseaWhsIn, overseaWhsInDtlList);
            if (checkInventory.getCode() != SUCCESS){
                return checkInventory;
            }
        }else if (spmsStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getCode())){
            /** 撤销单据，提交SAP失败——入库完成，5-1（减库存），需判断入库任务明细行数据储位库存是否够扣减；*/
            ResponseResult checkInventory = checkMaterialInventory(overseaWhsIn, overseaWhsInDtlList);
            if (checkInventory.getCode() != SUCCESS){
                return checkInventory;
            }
        }else {
            return ResponseResult.error("请求单据状态禁止此操作");
        }
        return ResponseResult.success();
    }

    /***
     * @param overseaWhsIn
     * @param overseaWhsInDtlList
     * @return
     */
    ResponseResult checkMaterialInventory(OverseaWhsIn overseaWhsIn, List<OverseaWhsInDtl> overseaWhsInDtlList){
        for (OverseaWhsInDtl overseaWhsInDtl : overseaWhsInDtlList){
            String item = overseaWhsInDtl.getItem();
            String materialNo = overseaWhsInDtl.getMaterialNo();
            String storageInfo = overseaWhsInDtl.getStorageInfo();
            double actualQtyBasicUnit = overseaWhsInDtl.getActualQtyBasicUnit() == null ? 0 : StringUtils.isEmpty(overseaWhsInDtl.getActualQtyBasicUnit().toString()) ? 0 : overseaWhsInDtl.getActualQtyBasicUnit();
            double actualQtyUnitSales = overseaWhsInDtl.getActualQtyUnitSales() == null ? 0 : StringUtils.isEmpty(overseaWhsInDtl.getActualQtyUnitSales().toString()) ? 0 : overseaWhsInDtl.getActualQtyUnitSales();
            if (actualQtyUnitSales > 0 && actualQtyBasicUnit > 0){
                if (StringUtils.isEmpty(storageInfo)){
                    return ResponseResult.error("实收数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                }
                //storageInfoArray 结构参考：[{"storageUuid":"f17e13b4d9ad4d39ba55548eff544391","qty":100,"storageNo":"C010101"}]
                JSONArray storageInfoArray = JSONArray.parseArray(overseaWhsInDtl.getStorageInfo());
                for (int i = 0; i < storageInfoArray.size(); i ++){
                    JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                    String storageUuid = storageInfoObj.getString("storageUuid");
                    double qty = storageInfoObj.getDoubleValue("qty");
                    String storageNo = storageInfoObj.getString("storageNo");
                    if (qty > 0){
                        WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getWhsStorageInventory(storageUuid, materialNo);
                        if (whsStorageInventory == null){
                            return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                        }
                        if (qty > whsStorageInventory.getAvailableQty()){
                            return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    /** 根据前端传值，入库任务提交SAP 3-4，3-5，5-4，5-5； */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult toSapOverseaWhsIn(String uuidWhsIn, String postingDate, int dataVersion, String userId) {
        try {
            ResponseResult checkToSapResult = checkToSap(uuidWhsIn, postingDate, dataVersion);
            if (checkToSapResult.getCode() != SUCCESS){
                return checkToSapResult;
            }
            QueryWrapper<OverseaWhsIn> queryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
            OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(queryWrapper);
            JSONObject dataToSap = formatDataToSap(uuidWhsIn, postingDate);
            log.info("=======dataToSap=========\n" + dataToSap);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("=======message=========\n" + message);
            JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            if (SAP_SUCCESS.equals(RETURN_DATA.getString("O_TYPE"))){
                String sapVoucherNumber = RETURN_DATA.getJSONArray("IT_MSG").getJSONObject(0).getString("MBLNR");
                String sapVoucherYear = RETURN_DATA.getJSONArray("IT_MSG").getJSONObject(0).getString("MJAHR");
                overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_SUBMIT_SAP.getCode());
                overseaWhsIn.setPostingDate(postingDate);
                overseaWhsIn.setSapVoucherNumber(sapVoucherNumber);
                overseaWhsIn.setSapVoucherYear(sapVoucherYear);
                this.baseMapper.update(overseaWhsIn, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, overseaWhsIn.getUuidWhsIn(), OVERSEA_WHS_IN_SUBMIT_SAP.getDescZh(),
                        OVERSEA_WHS_IN_SUBMIT_SAP.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "入库任务提交SAP");
                return ResponseResult.success()
                        .add("sapReturnedMessage", message)
                        .add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper))
                        .add("overseaWhsInDtl", iOverseaWhsInDtlService.getOverseaWhsInDtlList(uuidWhsIn))
                        .add("dataToSap", dataToSap);
            } else {
                overseaWhsIn.setSpmsStatus(OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getCode());
                overseaWhsIn.setPostingDate(postingDate);
                this.baseMapper.update(overseaWhsIn, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, overseaWhsIn.getUuidWhsIn(), OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getDescZh(),
                        OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "入库任务提交SAP");
                return ResponseResult.error()
                        .add("sendSapReturnedMessage", message)
                        .add("overseaWhsIn", this.baseMapper.selectOne(queryWrapper))
                        .add("dataToSap", dataToSap);
            }
        }catch (FeignException feignException){
            feignException.printStackTrace();
            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("提交SAP失败 Exception").add("error", e.getMessage());
        }
    }

    ResponseResult checkToSap(String uuidWhsIn, String postingDate, int dataVersion){
        if (StringUtils.isEmpty(uuidWhsIn) || StringUtils.isEmpty(postingDate)){
            return ResponseResult.error("请求参数错误");
        }
        if (INVALID_DATE.equals(postingDate)){
            return ResponseResult.error("过账日期格式错误请重试");
        }
        QueryWrapper<OverseaWhsIn> queryWrapper = new QueryWrapper<OverseaWhsIn>().eq("UUID_WHS_IN", uuidWhsIn);
        OverseaWhsIn overseaWhsIn = this.baseMapper.selectOne(queryWrapper);
        if (overseaWhsIn == null){
            return ResponseResult.error("请求入库任务不存在");
        }
        if (dataVersion != overseaWhsIn.getDataVersion()){
            return ResponseResult.error("请求数据已更新请刷新重试");
        }
        String spmsStatus = overseaWhsIn.getSpmsStatus();
        if (!spmsStatus.equals(OVERSEA_WHS_IN_APPROVE.getCode()) && !spmsStatus.equals(OVERSEA_WHS_IN_SUBMIT_SAP_ERROR.getCode())){
            return ResponseResult.error("任务当前状态禁止此操作");
        }
        List<OverseaWhsInDtl> overseaWhsInDtlList = iOverseaWhsInDtlService.getOverseaWhsInDtls(uuidWhsIn);
        if (overseaWhsInDtlList == null || overseaWhsInDtlList.size() == 0){
            return ResponseResult.error("请求入库任务明细行不存在");
        }
        return ResponseResult.success();
    }

    JSONObject formatDataToSap(String uuidWhsIn, String postingDate){
        JSONObject doc = new JSONObject();

        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
        REQUEST_DATA.put("Head", this.baseMapper.getWhsInToSap(uuidWhsIn, postingDate));
        REQUEST_DATA.put("Items", this.baseMapper.getWhsInDtlToSap(uuidWhsIn));
        REQUEST_DATA.put("Operation", "Z_SPMS_MIGO");
        REQUEST_DATA.put("Type", "SPMS_MIGO");
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        doc.put("REQUEST", REQUEST);
        return doc;
    }

    @Override
    public List<Map<String, Object>> getOverseaWhsInList(String sapDeliveryNote) {
        if (StringUtils.isEmpty(sapDeliveryNote)){
            return null;
        }
        return this.baseMapper.getOverseaWhsInList(sapDeliveryNote);
    }
}
